#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include "sobjc-commons/utils.h"
#include "sobjc-commons/defines.h"

#define ENV_TMPDIR          "TMPDIR"
#define ENV_TMP             "TMP"
#define ENV_TEMP            "TEMP"
#define DEFAULT_TEMP_DIR    "/tmp"
#define UNIQUE_NAME_SIZE    8

char *_objc_temp_dir = NULL;

char *
objc_get_temp_dir()
{
  char *temp_dir = NULL;

  /* environment TMPDIR, TMP, TEMP, "/tmp" */
  if (temp_dir == NULL)
    temp_dir = getenv(ENV_TMPDIR);
  if (temp_dir == NULL)
    temp_dir = getenv(ENV_TMP);
  if (temp_dir == NULL)
    temp_dir = getenv(ENV_TEMP);
  if (temp_dir == NULL)
    temp_dir = objc_strdup(DEFAULT_TEMP_DIR);

  return temp_dir;
}

char *
objc_make_temp_name(const char *prefix, const char *suffix)
{
  char *name, *temp;

  name = objc_make_unique_name(prefix, suffix);
  temp = objc_join_path_comps(objc_get_temp_dir(), name, NULL);

  objc_free(name);
  return temp;
}

char *
objc_make_unique_name(const char *prefix, const char *suffix)
{
  char *name;
  size_t plen = 0, slen = 0;
  int i;
  char c;

  if (prefix != NULL)
    plen = strlen(prefix);
  if (suffix != NULL)
    slen = strlen(suffix);

  name = ALLOC_N(char, UNIQUE_NAME_SIZE + plen + slen + 1);
  if (prefix != NULL)
    strcpy(name, prefix);
  if (suffix != NULL)
    strcpy((char *)(name + UNIQUE_NAME_SIZE + plen), suffix);

  srand((unsigned)time(NULL));
  for (i = 0; i < UNIQUE_NAME_SIZE; i++) {
    c = rand() % ('z'-'a'+'Z'-'A'+'9'-'0');
    if (c < 'z'-'a')
      c += 'a';
    else if (c < 'z'-'a'+'Z'-'A')
      c = c - ('z'-'a') + 'A';
    else
      c = c - ('z'-'a') - ('Z'-'A') + '0';
    name[plen+i] = c;
  }

  return name;
}

char *
objc_join_path_comps(char *comp, ...)
{
  va_list ap;
  char *path;

  va_start(ap, comp);
  path = objc_join_path_compv(comp, ap);
  va_end(ap);

  return path;
}

char *
objc_join_path_compv(char *comp, va_list ap)
{
  char *s, *path, **args;
  va_list copy;
  int size = 2, i = 0;

  VA_COPY(copy, ap);
  while ((s = va_arg(copy, char *)) != NULL)
    size++;

  args = ALLOC_N(char *, size);
  args[0] = objc_strdup(comp);
  while ((s = va_arg(ap, char *)) != NULL)
    args[1+i++] = s;
  args[size] = NULL;

  path = objc_join_path_compm(args);
  objc_free(args[0]);
  objc_free(args);

  return path;
}

char *
objc_join_path_compm(char **comps)
{
  char **s;
  char *path;
  int argc = 0, len = 0, l, i;

  s = comps;
  while (*s != NULL) {
    len += strlen(*s) + 1;
    s++;
    argc++;
  }

  path = ALLOC_N(char, len+1);
  s = comps;
  len = 0;
  i = 0;
  while (*s != NULL) {
    l = strlen(*s);
    strcpy(path+len, *s);
    len += l;
    i++;
    if (argc > i && (*s)[l-1] != '/')
      path[len++] = '/';
    s++;
  }
  path[len] = 0;

  return path;
}

char *
objc_join_path_comp_list(objc_str_list_t list)
{
  char **comps;
  char *path;

  comps = objc_str_list_to_array(list);
  path = objc_join_path_compm(comps);
  objc_free(comps);
  return path;
}

const char *
objc_get_path_ext(const char *path)
{
  return strchr(path, '.');
}

char *
objc_add_ext_to_path(const char *path, const char *ext)
{
  const char *old_ext;
  size_t size, body_size;
  char *new_path;

  size = strlen(path);
  old_ext = objc_get_path_ext(path);
  if (old_ext != NULL && strlen(ext) > strlen(old_ext))
    size += strlen(ext) - strlen(old_ext);
  new_path = ALLOC_N(char, size+1);
  body_size = strrchr(path, '.') - path;
  strncpy(new_path, path, body_size);
  sprintf(new_path + body_size, ".%s", ext);

  return new_path;
}

BOOL
objc_exists_file(const char *path)
{
  FILE *fp;

  if ((fp = fopen(path, "r")) == NULL)
    return NO;
  else {
    fclose(fp);
    return YES;
  }
}

int
objc_invoke_cmd(const char *path, int nargs, char **args)
{
  objc_str_list_t strs = NULL;
  int i, st;

  strs = objc_str_list_add(strs, path);
  for (i = 0; i < nargs; i++)
    strs = objc_str_list_add(strs, args[i]);
  st = objc_invoke_cmd_with_arg_list(strs);
  objc_str_list_free(strs);

  return st;
}

int
objc_invoke_cmd_with_arg_list(objc_str_list_t list)
{
  int st;
  char *s;

  s = objc_str_list_join(list, " ");
  st = system(s);
  objc_free(s);

  return st;
}
